<?php

namespace App\Services;

use App\Models\Recruit;
use App\Models\UserCollectRecruit;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;

class RecruitService extends BaseService
{
    public function getMapRecruitList(array $input): Collection|array
    {
        $latBetween = [$input['minLatitude'], $input['maxLatitude']];
        $LonBetween = [$input['minLongitude'], $input['maxLongitude']];
        $scale = $input['scale'] ?? 15;
        list($selectRegionNameField, $selectRegionIdField) = $this->getRegionInfoByScale($scale);
        $selectRegionNameFieldAlias = 'region_name';
        $rawSql = "count($selectRegionNameField) as recruit_count";

        $where[] = ['status', '=', 2];
        // 这个判断说明是用户点击了地图气泡请求数据的，不管是点击“区”级别还是“街道”级别，获取的都是最细颗粒度"区域"级别的数据
        if (isset($input['regionId']) && isset($input['selectType'])) {
            $where[] = [$this->getRegionIdFieldBySelectType($input['selectType']), '=', $input['regionId']];
        }

        $recruits = Recruit::query()
            ->whereBetween('latitude', $latBetween)
            ->whereBetween('longitude', $LonBetween)
            ->where($where)
            ->select($selectRegionNameField . ' as ' . $selectRegionNameFieldAlias, DB::raw($rawSql), 'longitude', 'latitude', $selectRegionIdField)
            ->groupBy($selectRegionNameField)
            ->get();

        // 优化中心经纬度的获取，这个待定看需不需要
        /*$centerLonLatsTable = $selectRegionIdField == 'region_id' ? 'district_id' : $selectRegionIdField;
        $centerLonLats = DB::table($centerLonLatsTable . ' as c')
            ->select('c.id', 'c.longitude', 'c.latitude')
            ->whereIn('c.id', $recruits->pluck($selectRegionIdField)->toArray())
            ->get();*/

        foreach ($recruits as $key => $recruit) {
            $recruits[$key]['map_mark_info'] = $recruit->$selectRegionNameFieldAlias . '(' . $recruit->recruit_count . '岗位)';
            $recruits[$key]['region_id'] = $recruit->$selectRegionIdField;
        }
        return $recruits;
    }

    /**
     * 根据地图缩放比例获取查询 “区域“和”区域id“ 信息
     * @param $scale
     * @return string[]
     */
    protected function getRegionInfoByScale($scale): array
    {
        if ($scale >= 15) {
            return ['region_name', 'region_id'];
        } elseif ($scale > 12 && $scale < 15) {
            return ['street', 'street_id'];
        } else {
            return ['district', 'district_id'];
        }
    }

    /**
     * 根据查询类型获取查询区域 id 字段名称
     * @param $selectType
     * @return string
     */
    protected function getRegionIdFieldBySelectType($selectType): string
    {
        return $selectType == 'district' ? 'district_id' : 'street_id';
    }

    public function getRecruitList(int $page, int $limit, string $sortField, string $orderRule, array $recruitTableColumns = ['*'],
                                   array $userTableColumns = ['*'], array $where = [], array $orWhere = []): array
    {
        $query = Recruit::with(['user' => function(BelongsTo $query) use ($userTableColumns) {
            $query->select($userTableColumns);
        }]);

        if (!empty($where)) {
            $query->where($where);
            if (isset($where['verify_type'])) {
                $query->whereRaw("FIND_IN_SET(?, verify_type)", [$where['verify_type']]);
            }
        }

        if (!empty($orWhere)) {
            $query->orWhere($orWhere);
        }

        if (!empty($sortField) && !empty($orderRule)) {
            $query = $query->orderBy($sortField, $orderRule);
        }

        $paginator = $query->paginate($limit, $recruitTableColumns, 'page', $page);
        return $this->optimizationPaginate($paginator);
    }

    /**
     * @param $input
     * @return Builder|Builder[]|Collection|Model|null
     */
    public function getRecruitDetail($input): Model|Collection|Builder|array|null
    {
        $recruitId = $input['recruit_id'];
        $recruitColumns = [
            "id", "user_id", "city", "recruit_cate_name", "recruit_desc",
            "created_at", "contact_phone", "title"
        ];
        $recruitDetail = Recruit::query()
            ->with(['user' => function (BelongsTo $query) {
                $query->select('id', 'avatar', 'nickname');
            }])
            ->find($recruitId, $recruitColumns);

        if (is_null($recruitDetail)) return null;

        $recruitDetail->is_collected = 0;
        $recruitDetail->collect_id = 0;

        if (!empty($input['user_id'])) {
            $userCollectRecruit = UserCollectRecruit::query()
                ->where(['user_id' => $input['user_id'], 'recruit_id' => $recruitId])
                ->first(['id', 'status']);

            if (!is_null($userCollectRecruit)) {
                $recruitDetail->is_collected = $userCollectRecruit->status;
                $recruitDetail->collect_id = $userCollectRecruit->id;
            }
        }
        return $recruitDetail;
    }

    public function getPublishRecruitDetail($input): array
    {
        return Recruit::query()->find($input['id']);
    }

    public function roundCoordinate($coordinate, $digits): float|int
    {
        $multiplier = pow(10, $digits);
        return round($coordinate * $multiplier) / $multiplier;
    }

    #deprecated 弃用
    public function getMapRecruitListDeprecated(array $input): Collection|array
    {
        $scale = $input['scale'] ?? 15;
        // 这个繁琐的 if-else 可以优化成一个方法，将 $regionName 和 $regionIdField 放在一个数组里返回
        if ($scale > 14) {
            $regionName = 'region_name';
            $regionIdField = 'region_id';
        } else if ($scale > 12 && $scale <= 14) {
            $regionName = 'street';
            $regionIdField = 'street_id';
        } else {
            $regionName = 'district';
            $regionIdField = 'district_id';
        }
        $regionNameAsName = 'region_name';
        $regionAsName = $regionName . ' as ' . $regionNameAsName;
        $rawSql = 'count(' . $regionName .') as recruit_count';
        $minLonLat = [$input['minLatitude'], $input['maxLatitude']];
        $maxLonLat = [$input['minLongitude'], $input['maxLongitude']];

        $where[] = ['status', '=', 2];
        // 这个繁琐的 if-else 同样也可以优化成一个方法
        if(isset($input['regionId']) && isset($input['selectType'])) {
            if ($input['selectType'] == 'district') {
                $where[] = ['district_id', '=', $input['regionId']];
            } else if ($input['selectType'] == 'street') {
                $where[] = ['street_id', '=', $input['regionId']];
            }
        }
        $recruits = Recruit::query()
            ->whereBetween('latitude', $minLonLat)
            ->whereBetween('longitude', $maxLonLat)
            ->where($where)
            ->select($regionAsName, DB::raw($rawSql), 'longitude', 'longitude', $regionIdField)
            ->groupBy($regionName)
            ->get();
        foreach ($recruits as $key => $recruit) {
            $recruits[$key]['map_mark_info'] = $recruit->region_name . '(' . $recruit->recruit_count . '岗位)';
            // 这里的表格获取和在 foreach 里的查询可以移到外面去
            if ($regionName == 'district') {
                $centerLonLat = DB::table('district')->where('id', '=', $recruit->district_id)->first(['longitude', 'latitude']);
                $recruits[$key]['region_id'] = $recruit->district_id;
            } else if ($regionName == 'street') {
                $centerLonLat = DB::table('street')->where('id', '=', $recruit->street_id)->first(['longitude', 'latitude']);
                $recruits[$key]['region_id'] = $recruit->street_id;
            }

            if (isset($centerLonLat)) {
                $recruits[$key]['centerLatitude'] = $centerLonLat->latitude;
                $recruits[$key]['centerLongitude'] = $centerLonLat->longitude;
            }
        }
        return $recruits;
        /* $radius      = 1000; // 搜索半径，单位：米
         $earthRadius = 6371000; // 地球半径，单位：米
         // 计算附近经纬度范围的上下限
         $latDiff = rad2deg($radius / $earthRadius);
         $lat1    = $this->roundCoordinate($latitude - $latDiff, 6);
         $lat2    = $this->roundCoordinate($latitude + $latDiff, 6);
         $lngDiff = rad2deg($radius / ($earthRadius * cos(deg2rad($latitude))));
         $lng1    = $this->roundCoordinate($longitude - $lngDiff, 6);
         $lng2    = $this->roundCoordinate($longitude + $lngDiff, 6);

         $recruits = Recruit::query()
                 ->whereBetween('latitude', [$lat1, $lat2])
                 ->whereBetween('longitude', [$lng1, $lng2])
                 ->where('status', 2)
                 ->select('region_name', DB::raw('count(region_name) as recruit_count'), 'longitude', 'latitude')
                 ->groupBy('region_name')
                 ->get();
         foreach ($recruits as $key => $recruit) {
             $recruits[$key]['map_mark_info'] = $recruit->region_name . '(' . $recruit->recruit_count . '岗位)';
         }
         return $recruits;*/
    }
}
